#region Header File
//
// Node.cs - Concurrent Code Block
//
// Copyright (C) Javier Valcarce. BSD License
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.Threading;
#endregion

namespace Dff
{
    /// <summary> Node status (running, stopped, idle, etc) </summary>
    public enum NodeStatus
    {
        Stopped,   // Data structures are not created, is the prior state before Aborted
        Paused,    // Data structures are kept but execution is paused
        Running,   // Normal work
        Shutdown   // All threads are ended. Respawn this node is no possible
    }

    /// <summary> Node parallel execution control </summary>
    public enum NodeCmdCtl
    {
        Start,   // Acquire resources and start execution
        Pause,   // Pause, don't free resources yet, the execution will continue
        Resume,  // Resume paused service
        Stop,    // Stop execution and free all resources (files, memory, etc)
        Shutdown // Terminate. No further execution is possible after this
    }


    /// <summary>
    /// Graph's Node Interface. Every DSP block in a graph must implement this interface. 
    /// </summary>   
    public abstract class Node 
    {
        #region Members
        /// <summary>
        /// Id of this node
        /// </summary>
        public int        Id                 { get; private set;   }
        /// <summary>
        /// Name of this node
        /// </summary>
        public string     Name               { get; private set;   }
        /// <summary>
        /// Status of this node
        /// </summary>
        public NodeStatus Status             { get; protected set; }
        /// <summary>
        /// Ports of this node
        /// </summary>
        public Dictionary<int, object> Ports { get; private set;   }

        // dispatcher of this concurrent node
        protected Dispatcher Dispatcher      { get; private set;   }

        // thread in which run the Dispatcher
        private Thread th;


        #endregion

        #region Events
        protected event DispatcherDelegate Load;
        protected event DispatcherDelegate Shutdown;
        protected event DispatcherDelegate Start;
        protected event DispatcherDelegate Stop;
        protected event DispatcherDelegate Pause;
        protected event DispatcherDelegate Resume;
        #endregion

        #region Constructors
        /// <summary>
        /// Base constructor: adds the node to Graph. NodeList
        /// </summary>
        public Node(string name)
        {
            this.Name       = name;
            this.Status     = NodeStatus.Stopped;
            this.Ports      = new Dictionary<int, object>();
            this.Dispatcher = new Dispatcher();

            th              = new Thread(MainThread);
            th.Name         = name;
            th.IsBackground = true;
            th.Start();
        }
        #endregion


        #region Public Methods
        /// <summary>
        /// Controls the execution of this node
        /// </summary>
        /// <param name="cmd">Command</param>
        /// <returns>Code Error</returns>
        public void Control(NodeCmdCtl cmd)
        {            
            switch (cmd)
            {
                case NodeCmdCtl.Start:
                    if (Status != NodeStatus.Stopped)
                        throw new Exception("Stop* the node first");

                    if (Start != null) Start(null);
                    Status = NodeStatus.Running;
                    break;

                case NodeCmdCtl.Pause:
                    if (Status != NodeStatus.Running)
                        throw new Exception("Start the node first");

                    if (Pause != null) Pause(null);
                    Status = NodeStatus.Paused;
                    break;

                case NodeCmdCtl.Resume:
                    if (Status != NodeStatus.Paused)
                        throw new Exception("Pause the node first");

                    if (Resume != null) Resume(null);
                    Status = NodeStatus.Running;
                    break;

                case NodeCmdCtl.Stop:
                    if ((Status != NodeStatus.Running) && 
                        (Status != NodeStatus.Paused))
                        throw new Exception("Start the node first");
                    
                    if (Stop != null) Stop(null);
                    Status = NodeStatus.Stopped;
                    break;

                case NodeCmdCtl.Shutdown:
                    if (Status != NodeStatus.Stopped)
                        throw new Exception("Stop* the node first");

                    if (Shutdown != null) Shutdown(null);
                    Status = NodeStatus.Shutdown;
                    Dispatcher.BeginInvokeShutdown();
                    break;
            }
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Thread with a Dispatcher
        /// </summary>
        private void MainThread()
        {
                        
            if (Load != null) Load(null);                     
            Dispatcher.Run();
        }
        #endregion
    }

}
